Skip to content

Fix application startup failure with springdoc.show-actuator=true and a separate management port - #590

Open
clun wants to merge 1 commit into
mainfrom
clun/issue-736-spring-boot-actuator
Open

Fix application startup failure with springdoc.show-actuator=true and a separate management port#590
clun wants to merge 1 commit into
mainfrom
clun/issue-736-spring-boot-actuator

Conversation

@clun

@clun clun commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Applications using the FF4J Spring Boot starter fail to start when springdoc's actuator
support is enabled with a management port different from the server port:

springdoc:
  show-actuator: true
management:
  server:
    port: 9090   # different from server.port

Startup fails with:

Error creating bean with name 'springdocBeanFactoryPostProcessor3' defined in class path resource
[org/springdoc/core/configuration/SpringDocConfiguration$SpringDocActuatorConfiguration.class]:
...
Failed to instantiate [org.ff4j.spring.boot.autoconfigure.common.FF4JOpenApiConfiguration]:
No default constructor found
Caused by: java.lang.NoSuchMethodException: org.ff4j.spring.boot.autoconfigure.common.FF4JOpenApiConfiguration.<init>()

This was originally reported against ff4j-spring-boot-autoconfigure 1.9 (Spring Boot 2.6 /
springdoc 1.6) and is still reproducible on current main with Spring Boot 4.1.0 and
springdoc 3.0.3.

Root cause

When springdoc.show-actuator=true and the management port differs from the server port,
springdoc registers springdocBeanFactoryPostProcessor3, a BeanFactoryPostProcessor whose
constructor depends on List<GroupedOpenApi>. Resolving that list forces Spring to instantiate
FF4JOpenApiConfiguration (the factory of FF4J's GroupedOpenApi bean) during the
bean-factory-post-processing phase — before any BeanPostProcessor is registered.

At that point in the container lifecycle:

  1. AutowiredAnnotationBeanPostProcessor is not registered yet, so Spring cannot resolve the
    parameterized constructor of FF4JOpenApiConfiguration and falls back to a default
    constructor, which does not exist → NoSuchMethodException.
  2. Even if instantiation succeeded, ConfigurationPropertiesBindingPostProcessor is not
    registered either, so any @ConfigurationProperties bean created this early would remain
    unbound forever — user settings like ff4j.api.spring-doc.group and
    ff4j.api.context-path would be silently ignored (the singleton is created once and never
    post-processed).

Fix

FF4JOpenApiConfiguration no longer uses constructor injection, so it is safe to instantiate at
any lifecycle phase:

  • The class now has a default constructor.
  • The GroupedOpenApi bean method resolves FF4J settings by binding them directly from the
    Environment via Binder.get(environment).bindOrCreate("ff4j", ...) instead of injecting the
    FF4JConfigurationProperties bean. The Environment is registered as a resolvable dependency
    before bean-factory post-processing, so this works during early instantiation and honors the
    user's configured values (addressing point 2 above).
  • The side effect previously in the init block (excluding FF4J paths from the OpenAPI
    documentation when ff4j.api.spring-doc.enabled is false) is moved to a dedicated
    InitializingBean that runs in the normal bean lifecycle, guarded by
    @ConditionalOnProperty(..., havingValue = "false", matchIfMissing = true) — same semantics
    as before. SpringDocConfigProperties is consumed through an ObjectProvider, preserving the
    previous lenient behavior in contexts where springdoc is on the classpath but inactive
    (e.g. non-web applications).

Testing

  • New regression test FF4JOpenApiActuatorConfigurationTest reproduces the reported setup
    (springdoc.show-actuator=true, management.server.port different from server.port,
    ff4j.api.spring-doc.enabled=true). It failed with the reported No default constructor found
    error before the fix and passes after. It also asserts that a custom
    ff4j.api.spring-doc.group value is correctly bound during early instantiation, guarding
    against the silent-unbound-properties regression.
  • spring-boot-starter-actuator and spring-boot-starter-web were added to
    ff4j-spring-boot-autoconfigure-common in test scope only to support the regression test.
  • Full reactor build passes: 8 modules, 153 tests, 0 failures.

Changed files

File Change
ff4j-spring-boot-autoconfigure-common/src/main/kotlin/.../FF4JOpenApiConfiguration.kt Default constructor, Binder-based property resolution, exclusion logic moved to InitializingBean
ff4j-spring-boot-autoconfigure-common/src/test/kotlin/.../FF4JOpenApiActuatorConfigurationTest.kt New regression test
ff4j-spring-boot-autoconfigure-common/pom.xml Test-scoped spring-boot-starter-actuator and spring-boot-starter-web

Fixes bug 736 in ff4j core repo

@clun
clun requested a review from a team as a code owner August 3, 2026 21:15
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.71%. Comparing base (83dfcd7) to head (9189497).
⚠️ Report is 106 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main     #590      +/-   ##
============================================
+ Coverage     87.69%   95.71%   +8.02%     
- Complexity      188      246      +58     
============================================
  Files            51       51              
  Lines           520      514       -6     
  Branches         21       20       -1     
============================================
+ Hits            456      492      +36     
+ Misses           53       12      -41     
+ Partials         11       10       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Conflict Documents Spring Boot actuator endpoints with OpenApi

1 participant